package core;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedList;

public class Map
{
    Vertex start;
    Vertex end;
    int mode;// -1 :drive  0:walk  1:bus

    String pathStr;
    String lengthStr;
    String des;
    String info;


    private int vertexSize=26;

    Vertex []vertexes;
    Edge [][]edges;

    private static final double INFINITY =Double.MAX_VALUE;

    public static void main(String []args)
    {
        Map map=new Map();
    }

    public Map()
    {
        resetStr();
        setGraph();
    }

    public String getInfo()
    {
        return info;
    }
    public Vertex[] getVertexes(){return vertexes;}
    public Vertex getStart(){return start;}

    public Vertex getEnd()
    {
        return end;
    }

    public void setGraph()
    {
        Graph graph=new Graph(vertexSize);
        vertexes=graph.vertexes;
        edges=graph.edges;
    }
    public void set2Ends(char start,char end)
    {
       this.start=vertexes[start-'A'];
       this.end=vertexes[end-'A'];
    }
    public void setMode(int mode)
    {
        this.mode=mode;
    }
    public void reset()
    {
        start=null;
        end=null;
        resetVertexes();
        resetStr();
    }
    public void resetStr()
    {
        pathStr="path: ";
        lengthStr="length: ";
        des="des: ";
        info="";
    }
    public void resetVertexes()
    {
        for (Vertex vertex:vertexes)
        {
            vertex.reset();
        }
    }

    //给定起点，终点，出行模式
    public void method1(char start,char end,int mode)
    {
        reset();
        set2Ends(start,end);
        setMode(mode);

        Edge tmp;
        this.start.setWeight(0);
        char vName;
        char wName;

        while (!this.end.getKnown())
        {
            Vertex v=getMinVertex();
            v.setKnown(true);
            LinkedList<Vertex> adjacent=v.getAdjacent();

            for (Vertex w:adjacent)
            {
                if (!w.getKnown())
                {
                    vName=v.getName();
                    wName=w.getName();

                    tmp=edges[vName-'A'][wName-'A'];
                    if(!canPass(tmp))
                        continue;

                    double cvw=tmp.getWeight(mode);//getCVW(v,w)  和mode有关
                    if (cvw<0)//处理虚拟公交边
                        continue;

                    if (v.getWeight()+cvw<w.getWeight())
                    {
                        w.setWeight(cvw+v.getWeight());
                        w.setPath(v);
                    }
                }
            }
        }
    }
    public boolean canPass(Edge edge)
    {
        switch (mode)
        {
            case -1:return edge.getDrive();
            case 0:return edge.getWalk();
            case 1:return edge.getBus()||edge.getWalk();
        }
        return false;
    }
    public Vertex getMinVertex()
    {
        int index=0;
        double minWeight=INFINITY;
        for (int i=0;i<vertexes.length;i++)
        {
            if (!vertexes[i].getKnown()&&vertexes[i].getWeight()<=minWeight)
            {
                index=i;
                minWeight=vertexes[i].getWeight();
                double weight=minWeight;
            }
        }
        return vertexes[index];
    }

   public void setPathStr(Vertex vertex)
   {
       if (vertex.getPath()!=null)
       {
           setPathStr(vertex.getPath());
           pathStr+="-->";
       }
       pathStr+=vertex.getName();
   }
   public void setDes(Vertex vertex)
   {
       Vertex path=vertex.getPath();
       if (path!=null)
       {
           setDes(path);

           Edge edge=edges[path.getName()-'A'][vertex.getName()-'A'];
           if (!edge.getByBus())
           {
               des+=edge.start+"-->"+edge.end+":walk"+" ";
           }

       }
   }
   public void setLengthStr()
   {
       if (mode>0)
           this.lengthStr+=end.getWeight()+" min";
       else
           this.lengthStr+=end.getWeight()+" km";
   }
   public void setInfo()
   {
       switch (mode)
       {
           case -1:info="Drive Mode:\n";break;
           case 1:info="Bus Mode:\n";break;
           default:info="Walk Mode:\n";
       }
       if (end.getPath()==null)
       {
           info+="We can't find the way by this mean,you can try to choose other mean";
       }
       else
       {
           setPathStr(end);
           setLengthStr();
           if (mode>0)
               setDes(end);
           info+=pathStr+"\n"+lengthStr+"\n"+des;
       }
   }



   //给定一个点，将其他点到该点的最短路径，
    public String method2(char v,int mode)
    {
        String tmp="";
        for (int i=0;i<vertexes.length;i++)
        {
            if (i!=(v-'A'))
            {
                method1((char)(i+'A'),v,mode);
                double length=end.getWeight();
                if (length==INFINITY)
                    continue;

                tmp+=start.getName()+"-->"+end.getName()+" length:"+length;

                if (mode>0)
                    tmp+=" min"+"\n";
                else
                    tmp+=" km"+"\n";
            }
        }
        return tmp;
    }
    public void generateFile2(char v,int mode) throws IOException
    {
        String method2=method2(v,mode);
        String fileName="./shortestPath/"+v;
        switch (mode)
        {
            case -1:fileName+="_drive";break;
            case 0:fileName+="_walk";break;
            case 1:fileName+="_bus";break;
        }
        fileName+=".txt";

        File file=new File(fileName);
        PrintWriter output=new PrintWriter(file);
        output.print(method2);
        output.close();

    }

    //输出任意两点间的最短路径
    public String method3(int mode)
    {
        String tmp="";
        for (int i=0;i<vertexes.length;i++)
        {
            tmp+=method2((char)(i+'A'),mode);
        }
        return tmp;
    }
    public void generateFile3(int mode) throws IOException
    {
        String method3=method3(mode);
        String fileName="./shortestPath/all";
        switch (mode)
        {
            case -1:fileName+="_drive";break;
            case 0:fileName+="_walk";break;
            case 1:fileName+="_bus";break;
        }
        fileName+=".txt";
        File file=new File(fileName);

        PrintWriter output=new PrintWriter(file);
        output.print(method3);
        output.close();

    }
}
